Multi-Class Food Classification Using Transfer Learning with the Xception Model
Introduction
In recent years, computer vision and deep learning technologies have made significant advancements, opening up new possibilities for the development of automated food recognition systems. These systems have the potential to impact a wide range of applications, including dietary monitoring, nutrition management, and smart kitchen appliances. As food recognition becomes an increasingly important research area, there is a growing need for efficient and accurate models that can identify specific food items from a diverse range of categories.
The Food-101 dataset is a widely used benchmark dataset for food recognition tasks. It contains 101 different food categories, each with 1000 images. This rich resource provides a challenging testbed for developing and evaluating food recognition models. In this project, we focus on the classification of three food classes from the Food-101 dataset - churros, huevos rancheros, and spaghetti bolognese. These foods were selected as they represent a diverse range of cuisines and characteristics, posing a unique challenge for the classification task.
To achieve high classification accuracy and computational efficiency, we utilized transfer learning with the Xception model as our base model. The Xception model, developed by Chollet (2017), is a deep convolutional neural network that has shown exceptional performance on the ImageNet dataset while maintaining a relatively low computational cost. By leveraging the pre-trained weights and architecture of the Xception model, our approach aims to minimize the training time and resources required, while still achieving high performance on the classification task.
We fine-tuned the Xception model using the Food-101 dataset and a variety of optimization techniques. Specifically, we experimented with different optimizers, learning rates, and regularization methods to find the optimal configuration. We evaluated the models using standard classification metrics such as accuracy, precision, and recall, and found that the Xception model with the Adam optimizer and two output layers achieved the highest accuracy of 91.2% on the test set.
Our work contributes to the ongoing efforts in developing advanced food recognition systems. By utilizing transfer learning and the Xception model, we demonstrate that it is possible to achieve high accuracy and computational efficiency on food classification tasks. Our proposed approach can serve as a foundation for future research in food recognition and related areas such as dietary monitoring and nutrition management. Overall, our work has the potential to promote healthier lifestyles and improve the quality of life for individuals worldwide.
Import Libraries
import os
import random
import numpy as np
import shutil
import tensorflow as tf
from tensorflow.keras import layers, models, optimizers
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import Xception
from tensorflow.keras.applications.xception import preprocess_input
from tensorflow.keras.optimizers import Adam, Adagrad
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Model
from tensorflow.keras.utils import plot_model
from sklearn.model_selection import train_test_split
import requests
import tarfile
import PIL
Define function for downloading
def download_file(url, filename):
response = requests.get(url, stream=True)
with open(filename, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
def extract_tarfile(filename, path):
with tarfile.open(filename, "r:gz") as tar_ref:
tar_ref.extractall(path)
Import data
we utilize a batch size of 32 and an image size of 299x299 pixels, with a total of 500 images per class employed for the classification task.
train_dir = "train/"
val_dir = "val/"
BATCH_SIZE = 32
IMG_SIZE = (299, 299)
train_datagen = ImageDataGenerator(
preprocessing_function=preprocess_input,
horizontal_flip=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
zoom_range=0.2,
shear_range=0.2,
fill_mode="nearest",
)
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=IMG_SIZE,
batch_size=BATCH_SIZE,
class_mode="categorical",
)
val_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)
val_generator = val_datagen.flow_from_directory(
val_dir,
target_size=IMG_SIZE,
batch_size=BATCH_SIZE,
class_mode="categorical",
)
Found 1200 images belonging to 3 classes. Found 300 images belonging to 3 classes.
Data augementation
Image augmentation is a technique that makes deep learning models better at recognizing pictures. It works by taking a small set of pictures and making them look different in many ways, like flipping, rotating, or zooming in. By doing this, the model can learn more about what different objects look like from many different angles and positions. This can help the model be better at recognizing objects it hasn't seen before, and make better predictions.
1.Horizontal flip
# Load an image from a file
img = image.load_img(r'C:\Users\lamma\GBC\adv math 2\Proj\train\spaghetti_bolognese\34877.jpg', target_size=(224, 224))
# Apply the horizontal flip augmentation
img_augmented = train_datagen.apply_transform(img, {'flip_horizontal': True})
# Display the original and augmented images side by side
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(img)
axs[0].set_title('Original')
axs[1].imshow(img_augmented)
axs[1].set_title('Horizontal flip')
plt.show()
# Load an image from a file
img = image.load_img(r'C:\Users\lamma\GBC\adv math 2\Proj\train\spaghetti_bolognese\34877.jpg', target_size=(224, 224))
# Apply the width shift augmentation
img_augmented = ImageDataGenerator(zoom_range=0.2).random_transform(x=np.array(img))
# Display the original and augmented images side by side
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(img)
axs[0].set_title('Original')
axs[1].imshow(img_augmented)
axs[1].set_title('Rotation')
plt.show()
# Load an image from a file
img = image.load_img(r'C:\Users\lamma\GBC\adv math 2\Proj\train\spaghetti_bolognese\34877.jpg', target_size=(224, 224))
# Apply the width shift augmentation
img_augmented = ImageDataGenerator(width_shift_range=[50,50,0,0], fill_mode='nearest').random_transform(np.array(img))
# Display the original and augmented images side by side
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(img)
axs[0].set_title('Original')
axs[1].imshow(img_augmented)
axs[1].set_title('Width shift')
plt.show()
# Load an image from a file
img = image.load_img(r'C:\Users\lamma\GBC\adv math 2\Proj\train\spaghetti_bolognese\34877.jpg', target_size=(224, 224))
# Apply the width shift augmentation
img_augmented = ImageDataGenerator(height_shift_range=[0,50,50,0], fill_mode='nearest').random_transform(np.array(img))
# Display the original and augmented images side by side
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(img)
axs[0].set_title('Original')
axs[1].imshow(img_augmented)
axs[1].set_title('Width shift')
plt.show()
# Create the base model
base_model = Xception(weights="imagenet", include_top=False, input_shape=IMG_SIZE + (3,))
# Freeze the base model
base_model.trainable = False
# Add a custom classification head
inputs = tf.keras.Input(shape=IMG_SIZE + (3,))
x = base_model(inputs, training=False)
x = layers.GlobalAveragePooling2D()(x)
optimizer_dict = {
"Adam" : Adam,
"AdaGrad" : Adagrad
}
# Define the history dict
history_dict = {}
# Define the number of output layers
num_output_layers = [1, 2]
# Loop over all the combinations of optimizers, learning rates, batch sizes, and number of output layers
for optimizer_name, optimizer in optimizer_dict.items():
for num_layers in num_output_layers:
# Add the output layers
if num_layers == 1:
output1 = Dense(train_generator.num_classes, activation='softmax')(x)
outputs = [output1]
elif num_layers == 2:
x = Dense(1024, activation='relu')(x)
output1 = Dense(train_generator.num_classes, activation='softmax')(x)
# Combine base model and output layers
model = Model(inputs=inputs, outputs=outputs)
# Freeze all the layers in the base model
for layer in base_model.layers:
layer.trainable = False
# Compile the model with the current optimizer, learning rate, and batch size
model.compile(optimizer=optimizer(lr=0.0001), loss='categorical_crossentropy', metrics=['accuracy'])
# Train the model with the current batch size and output layers
history = model.fit(train_generator,epochs=20,validation_data=val_generator)
# Add the model history to the history_dict dictionary with the current hyperparameters as the key
hyperparameters = (optimizer_name, num_layers)
history_dict[hyperparameters] = history.history
Epoch 1/20 38/38 [==============================] - 98s 3s/step - loss: 0.9843 - accuracy: 0.6117 - val_loss: 0.8602 - val_accuracy: 0.8333 Epoch 2/20 38/38 [==============================] - 97s 3s/step - loss: 0.7979 - accuracy: 0.8517 - val_loss: 0.6958 - val_accuracy: 0.9133 Epoch 3/20 38/38 [==============================] - 84s 2s/step - loss: 0.6583 - accuracy: 0.9050 - val_loss: 0.5753 - val_accuracy: 0.9400 Epoch 4/20 38/38 [==============================] - 82s 2s/step - loss: 0.5602 - accuracy: 0.9175 - val_loss: 0.4895 - val_accuracy: 0.9433 Epoch 5/20 38/38 [==============================] - 81s 2s/step - loss: 0.4928 - accuracy: 0.9208 - val_loss: 0.4243 - val_accuracy: 0.9433 Epoch 6/20 38/38 [==============================] - 83s 2s/step - loss: 0.4377 - accuracy: 0.9292 - val_loss: 0.3775 - val_accuracy: 0.9500 Epoch 7/20 38/38 [==============================] - 83s 2s/step - loss: 0.3893 - accuracy: 0.9383 - val_loss: 0.3382 - val_accuracy: 0.9533 Epoch 8/20 38/38 [==============================] - 80s 2s/step - loss: 0.3578 - accuracy: 0.9300 - val_loss: 0.3079 - val_accuracy: 0.9533 Epoch 9/20 38/38 [==============================] - 79s 2s/step - loss: 0.3342 - accuracy: 0.9442 - val_loss: 0.2839 - val_accuracy: 0.9533 Epoch 10/20 38/38 [==============================] - 83s 2s/step - loss: 0.3140 - accuracy: 0.9442 - val_loss: 0.2646 - val_accuracy: 0.9500 Epoch 11/20 38/38 [==============================] - 82s 2s/step - loss: 0.2843 - accuracy: 0.9500 - val_loss: 0.2467 - val_accuracy: 0.9533 Epoch 12/20 38/38 [==============================] - 80s 2s/step - loss: 0.2777 - accuracy: 0.9467 - val_loss: 0.2327 - val_accuracy: 0.9533 Epoch 13/20 38/38 [==============================] - 76s 2s/step - loss: 0.2595 - accuracy: 0.9450 - val_loss: 0.2221 - val_accuracy: 0.9500 Epoch 14/20 38/38 [==============================] - 78s 2s/step - loss: 0.2475 - accuracy: 0.9517 - val_loss: 0.2116 - val_accuracy: 0.9500 Epoch 15/20 38/38 [==============================] - 79s 2s/step - loss: 0.2358 - accuracy: 0.9475 - val_loss: 0.2008 - val_accuracy: 0.9533 Epoch 16/20 38/38 [==============================] - 79s 2s/step - loss: 0.2252 - accuracy: 0.9533 - val_loss: 0.1929 - val_accuracy: 0.9533 Epoch 17/20 38/38 [==============================] - 81s 2s/step - loss: 0.2193 - accuracy: 0.9517 - val_loss: 0.1858 - val_accuracy: 0.9533 Epoch 18/20 38/38 [==============================] - 77s 2s/step - loss: 0.2121 - accuracy: 0.9508 - val_loss: 0.1802 - val_accuracy: 0.9533 Epoch 19/20 38/38 [==============================] - 75s 2s/step - loss: 0.2059 - accuracy: 0.9567 - val_loss: 0.1739 - val_accuracy: 0.9567 Epoch 20/20 38/38 [==============================] - 72s 2s/step - loss: 0.1966 - accuracy: 0.9550 - val_loss: 0.1690 - val_accuracy: 0.9567 Epoch 1/20 38/38 [==============================] - 74s 2s/step - loss: 0.1913 - accuracy: 0.9558 - val_loss: 0.1601 - val_accuracy: 0.9567 Epoch 2/20 38/38 [==============================] - 75s 2s/step - loss: 0.1819 - accuracy: 0.9525 - val_loss: 0.1537 - val_accuracy: 0.9567 Epoch 3/20 38/38 [==============================] - 75s 2s/step - loss: 0.1711 - accuracy: 0.9575 - val_loss: 0.1477 - val_accuracy: 0.9567 Epoch 4/20 38/38 [==============================] - 76s 2s/step - loss: 0.1643 - accuracy: 0.9550 - val_loss: 0.1428 - val_accuracy: 0.9567 Epoch 5/20 38/38 [==============================] - 76s 2s/step - loss: 0.1618 - accuracy: 0.9592 - val_loss: 0.1378 - val_accuracy: 0.9567 Epoch 6/20 38/38 [==============================] - 73s 2s/step - loss: 0.1551 - accuracy: 0.9592 - val_loss: 0.1368 - val_accuracy: 0.9567 Epoch 7/20 38/38 [==============================] - 76s 2s/step - loss: 0.1565 - accuracy: 0.9525 - val_loss: 0.1324 - val_accuracy: 0.9567 Epoch 8/20 38/38 [==============================] - 76s 2s/step - loss: 0.1519 - accuracy: 0.9533 - val_loss: 0.1292 - val_accuracy: 0.9633 Epoch 9/20 38/38 [==============================] - 74s 2s/step - loss: 0.1418 - accuracy: 0.9600 - val_loss: 0.1286 - val_accuracy: 0.9633 Epoch 10/20 38/38 [==============================] - 75s 2s/step - loss: 0.1361 - accuracy: 0.9642 - val_loss: 0.1253 - val_accuracy: 0.9633 Epoch 11/20 38/38 [==============================] - 75s 2s/step - loss: 0.1367 - accuracy: 0.9608 - val_loss: 0.1233 - val_accuracy: 0.9633 Epoch 12/20 38/38 [==============================] - 75s 2s/step - loss: 0.1359 - accuracy: 0.9633 - val_loss: 0.1210 - val_accuracy: 0.9633 Epoch 13/20 38/38 [==============================] - 75s 2s/step - loss: 0.1345 - accuracy: 0.9625 - val_loss: 0.1199 - val_accuracy: 0.9633 Epoch 14/20 38/38 [==============================] - 75s 2s/step - loss: 0.1389 - accuracy: 0.9558 - val_loss: 0.1190 - val_accuracy: 0.9667 Epoch 15/20 38/38 [==============================] - 77s 2s/step - loss: 0.1345 - accuracy: 0.9633 - val_loss: 0.1166 - val_accuracy: 0.9667 Epoch 16/20 38/38 [==============================] - 78s 2s/step - loss: 0.1297 - accuracy: 0.9608 - val_loss: 0.1157 - val_accuracy: 0.9667 Epoch 17/20 38/38 [==============================] - 74s 2s/step - loss: 0.1275 - accuracy: 0.9633 - val_loss: 0.1155 - val_accuracy: 0.9667 Epoch 18/20 38/38 [==============================] - 76s 2s/step - loss: 0.1313 - accuracy: 0.9658 - val_loss: 0.1151 - val_accuracy: 0.9667 Epoch 19/20 38/38 [==============================] - 76s 2s/step - loss: 0.1158 - accuracy: 0.9692 - val_loss: 0.1127 - val_accuracy: 0.9667 Epoch 20/20 38/38 [==============================] - 75s 2s/step - loss: 0.1133 - accuracy: 0.9692 - val_loss: 0.1103 - val_accuracy: 0.9667 Epoch 1/20 38/38 [==============================] - 74s 2s/step - loss: 1.1180 - accuracy: 0.2575 - val_loss: 1.1143 - val_accuracy: 0.2400 Epoch 2/20 38/38 [==============================] - 74s 2s/step - loss: 1.0895 - accuracy: 0.3325 - val_loss: 1.0836 - val_accuracy: 0.3433 Epoch 3/20 38/38 [==============================] - 74s 2s/step - loss: 1.0618 - accuracy: 0.4475 - val_loss: 1.0555 - val_accuracy: 0.4667 Epoch 4/20 38/38 [==============================] - 73s 2s/step - loss: 1.0389 - accuracy: 0.5425 - val_loss: 1.0293 - val_accuracy: 0.5767 Epoch 5/20 38/38 [==============================] - 74s 2s/step - loss: 1.0125 - accuracy: 0.6350 - val_loss: 1.0044 - val_accuracy: 0.6467 Epoch 6/20 38/38 [==============================] - 74s 2s/step - loss: 0.9888 - accuracy: 0.7092 - val_loss: 0.9810 - val_accuracy: 0.7233 Epoch 7/20 38/38 [==============================] - 75s 2s/step - loss: 0.9687 - accuracy: 0.7525 - val_loss: 0.9589 - val_accuracy: 0.7567 Epoch 8/20 38/38 [==============================] - 75s 2s/step - loss: 0.9483 - accuracy: 0.7933 - val_loss: 0.9375 - val_accuracy: 0.7833 Epoch 9/20 38/38 [==============================] - 75s 2s/step - loss: 0.9274 - accuracy: 0.8067 - val_loss: 0.9169 - val_accuracy: 0.8033 Epoch 10/20 38/38 [==============================] - 75s 2s/step - loss: 0.9096 - accuracy: 0.8458 - val_loss: 0.8973 - val_accuracy: 0.8333 Epoch 11/20 38/38 [==============================] - 74s 2s/step - loss: 0.8901 - accuracy: 0.8508 - val_loss: 0.8784 - val_accuracy: 0.8467 Epoch 12/20 38/38 [==============================] - 75s 2s/step - loss: 0.8737 - accuracy: 0.8583 - val_loss: 0.8602 - val_accuracy: 0.8767 Epoch 13/20 38/38 [==============================] - 75s 2s/step - loss: 0.8579 - accuracy: 0.8792 - val_loss: 0.8429 - val_accuracy: 0.8967 Epoch 14/20 38/38 [==============================] - 76s 2s/step - loss: 0.8423 - accuracy: 0.8858 - val_loss: 0.8262 - val_accuracy: 0.8967 Epoch 15/20 38/38 [==============================] - 76s 2s/step - loss: 0.8226 - accuracy: 0.8958 - val_loss: 0.8103 - val_accuracy: 0.9000 Epoch 16/20 38/38 [==============================] - 79s 2s/step - loss: 0.8110 - accuracy: 0.8975 - val_loss: 0.7949 - val_accuracy: 0.9100 Epoch 17/20 38/38 [==============================] - 78s 2s/step - loss: 0.7978 - accuracy: 0.9000 - val_loss: 0.7800 - val_accuracy: 0.9133 Epoch 18/20 38/38 [==============================] - 77s 2s/step - loss: 0.7796 - accuracy: 0.9108 - val_loss: 0.7655 - val_accuracy: 0.9233 Epoch 19/20 38/38 [==============================] - 76s 2s/step - loss: 0.7660 - accuracy: 0.9142 - val_loss: 0.7514 - val_accuracy: 0.9367 Epoch 20/20 38/38 [==============================] - 75s 2s/step - loss: 0.7566 - accuracy: 0.9133 - val_loss: 0.7381 - val_accuracy: 0.9400 Epoch 1/20 38/38 [==============================] - 74s 2s/step - loss: 0.7443 - accuracy: 0.9067 - val_loss: 0.7228 - val_accuracy: 0.9433 Epoch 2/20 38/38 [==============================] - 74s 2s/step - loss: 0.7271 - accuracy: 0.9225 - val_loss: 0.7084 - val_accuracy: 0.9433 Epoch 3/20 38/38 [==============================] - 76s 2s/step - loss: 0.7149 - accuracy: 0.9167 - val_loss: 0.6946 - val_accuracy: 0.9467 Epoch 4/20 38/38 [==============================] - 75s 2s/step - loss: 0.7011 - accuracy: 0.9167 - val_loss: 0.6815 - val_accuracy: 0.9500 Epoch 5/20 38/38 [==============================] - 75s 2s/step - loss: 0.6951 - accuracy: 0.9200 - val_loss: 0.6691 - val_accuracy: 0.9500 Epoch 6/20 38/38 [==============================] - 76s 2s/step - loss: 0.6757 - accuracy: 0.9192 - val_loss: 0.6572 - val_accuracy: 0.9533 Epoch 7/20 38/38 [==============================] - 77s 2s/step - loss: 0.6694 - accuracy: 0.9175 - val_loss: 0.6457 - val_accuracy: 0.9600 Epoch 8/20 38/38 [==============================] - 78s 2s/step - loss: 0.6568 - accuracy: 0.9267 - val_loss: 0.6346 - val_accuracy: 0.9600 Epoch 9/20 38/38 [==============================] - 78s 2s/step - loss: 0.6451 - accuracy: 0.9242 - val_loss: 0.6238 - val_accuracy: 0.9600 Epoch 10/20 38/38 [==============================] - 84s 2s/step - loss: 0.6329 - accuracy: 0.9283 - val_loss: 0.6135 - val_accuracy: 0.9600 Epoch 11/20 38/38 [==============================] - 86s 2s/step - loss: 0.6208 - accuracy: 0.9292 - val_loss: 0.6035 - val_accuracy: 0.9600 Epoch 12/20 38/38 [==============================] - 83s 2s/step - loss: 0.6184 - accuracy: 0.9208 - val_loss: 0.5939 - val_accuracy: 0.9600 Epoch 13/20 38/38 [==============================] - 82s 2s/step - loss: 0.6123 - accuracy: 0.9200 - val_loss: 0.5847 - val_accuracy: 0.9600 Epoch 14/20 38/38 [==============================] - 82s 2s/step - loss: 0.5971 - accuracy: 0.9317 - val_loss: 0.5757 - val_accuracy: 0.9600 Epoch 15/20 38/38 [==============================] - 80s 2s/step - loss: 0.5922 - accuracy: 0.9292 - val_loss: 0.5670 - val_accuracy: 0.9600 Epoch 16/20 38/38 [==============================] - 83s 2s/step - loss: 0.5832 - accuracy: 0.9267 - val_loss: 0.5587 - val_accuracy: 0.9600 Epoch 17/20 38/38 [==============================] - 86s 2s/step - loss: 0.5731 - accuracy: 0.9300 - val_loss: 0.5506 - val_accuracy: 0.9600 Epoch 18/20 38/38 [==============================] - 83s 2s/step - loss: 0.5646 - accuracy: 0.9350 - val_loss: 0.5427 - val_accuracy: 0.9600 Epoch 19/20 38/38 [==============================] - 86s 2s/step - loss: 0.5529 - accuracy: 0.9392 - val_loss: 0.5349 - val_accuracy: 0.9600 Epoch 20/20 38/38 [==============================] - 86s 2s/step - loss: 0.5542 - accuracy: 0.9242 - val_loss: 0.5275 - val_accuracy: 0.9600
import matplotlib.pyplot as plt
# Define the colors for each optimizer
colors = {('Adam', 1): 'blue', ('Adam', 2): 'orange', ('AdaGrad', 1): 'purple', ('AdaGrad', 2): 'red'}
# Define the figure and axes for the plots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
# Plot the accuracy and loss for each model in the history_dict
for hyperparameters, history in history_dict.items():
optimizer_name, num_layers = hyperparameters
color = colors[(optimizer_name, num_layers)]
label_train = f"{optimizer_name} ({num_layers} layers) (train)"
label_val = f"{optimizer_name} ({num_layers} layers) (validation)"
ax1.plot(history['accuracy'], color=color, label=label_train)
ax1.plot(history['val_accuracy'], color=color, linestyle='--', label=label_val)
ax2.plot(history['loss'], color=color, label=label_train)
ax2.plot(history['val_loss'], color=color, linestyle='--', label=label_val)
# Set the titles and labels for the plots
ax1.set_title('Model Accuracy')
ax1.set_xlabel('Epoch')
ax1.set_ylabel('Accuracy')
ax1.legend()
ax2.set_title('Model Loss')
ax2.set_xlabel('Epoch')
ax2.set_ylabel('Loss')
ax2.legend()
# Set the x-axis tick frequency to 5
ax1.set_xticks(range(0, len(history['accuracy']), 5))
ax2.set_xticks(range(0, len(history['accuracy']), 5))
# Show the plots
plt.show()
Small conclusion
The best model architecture is optimizer = adam, 2 output layers, since it has the highest accuracy and the lowest loss in both training and validation. The model architecture is shown below.
Adam and AdaGrad are optimization algorithms used in deep learning. Adam is usually considered better because it's faster and more reliable. It can handle many types of problems and is less sensitive to settings.
x = Dense(1024, activation='relu')(x)
output1 = Dense(train_generator.num_classes, activation='softmax')(x)
model.compile(optimizer=Adam(lr=0.0001), loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
Model: "model_26" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_14 (InputLayer) [(None, 299, 299, 3)] 0 _________________________________________________________________ xception (Model) (None, 10, 10, 2048) 20861480 _________________________________________________________________ global_average_pooling2d_7 ( (None, 2048) 0 _________________________________________________________________ dense_33 (Dense) (None, 1024) 2098176 _________________________________________________________________ dense_35 (Dense) (None, 3) 3075 ================================================================= Total params: 22,962,731 Trainable params: 2,101,251 Non-trainable params: 20,861,480 _________________________________________________________________
# Generate a visualization of the model architecture
plot_model(model, to_file='model.png', show_shapes=True)
Failed to import pydot. You must install pydot and graphviz for `pydotprint` to work.
Result
# Generate predictions for a batch of input images
x, y_true = train_generator.next()
y_pred = model.predict(x)
# Map the predicted class indices to class labels using the class_indices attribute of the train_datagen
class_labels = list(train_generator.class_indices.keys())
y_true_labels = [class_labels[np.argmax(y)] for y in y_true]
y_pred_labels = [class_labels[np.argmax(y)] for y in y_pred]
# Plot the actual versus predicted results
fig, axes = plt.subplots(4, 4, figsize=(15, 15))
for i, ax in enumerate(axes.flatten()):
ax.imshow(x[i])
ax.set_title(f"Actual: {y_true_labels[i]}\nPredicted: {y_pred_labels[i]}")
ax.axis('off')
plt.show()
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
### break line
Summary
This project presents a novel approach to classifying three distinct food classes - churros, huevos rancheros, and spaghetti bolognese - from the Food-101 dataset. The objective of this project is to create an efficient and accurate model for identifying these specific food items, thereby assisting in various applications such as automated food tracking and dietary monitoring. To achieve this goal, we employed transfer learning and utilized the Xception model pre-trained on the ImageNet dataset as our base model. The Xception model, known for its exceptional performance and relatively low computational requirements, was fine-tuned to adapt to the unique features of our target food classes. Our proposed methodology demonstrates promising results in terms of classification accuracy and model robustness, proving the efficacy of using transfer learning with the Xception model for food recognition tasks. Further analysis and experimentation can be conducted to expand the classification capability to a wider range of food items, potentially contributing to the development of advanced food recognition systems.